#define RUNTIME_DBG_LVL		0
#define FTEST			/* 关闭一些告警 */
/* 测试 */
/* 空函数，以避免额外的WCET */
#define WCET_PRINTF(...)	
/* 配置 */
#include "test_common.h"
#define TEST_MAXTHREADS		(2 * HDEF_NATIVE_CPU_NR)
#define TEST_NR			(10000000)
#define TEST_THREADNR		(HDEF_NATIVE_CPU_NR)

#if (HDEF_NATIVE_CPU_NR == 8)
	/* sdm888 先得创建线程唤醒大核 */
	#define WARMUP_THREAD_NR	(2 * HDEF_NATIVE_CPU_NR)
	#define TEST_MAXSZ_BATCH	(SIZE_8M)
	// static word_t test_nrs_arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
	static word_t test_nrs_arr[] = {8};
#elif (HDEF_NATIVE_CPU_NR == 16)
	#define WARMUP_THREAD_NR	(1)
	#define TEST_MAXSZ_BATCH	(SIZE_8M)
	// static word_t test_nrs_arr[] = {1, 2, 4, 6, 8, 11, 13, 16};
	static word_t test_nrs_arr[] = {16};
#elif (HDEF_NATIVE_CPU_NR == 24)
	#define WARMUP_THREAD_NR	(1)
	#define TEST_MAXSZ_BATCH	(SIZE_8M)
	// static word_t test_nrs_arr[] = {1, 2, 4, 8, 12, 16, 20, 24};
	static word_t test_nrs_arr[] = {24};
#endif


#include <dbg/ptest.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <metalc/base/mtls.h>
#include <pthreadalt.h>
#include <compl.h>

#include <unix/page_alloc_os.h>

#include <dinfra/mpwf/wmsp.h>
// #define POOL_SIZE (256 * 1024)
// static TLS_INITIAL wmobj_t *malloc_perm_pool_list;
// DEF_WMSP_OBJ_CACHED_HUGEPAGE(malloc_perm_pool, &malloc_perm_pool_list, HDEF_CACHE_LINE_BYTES, POOL_SIZE, SIZE_2M, mark_hugepage)
// /* 变成自己的size */
SIN void *mlcc_palloc(size_t size){ return page_alloc(size); }



/* 定义wcet */
#include <metalc/mladt/wcet_stat.h>

#include <metalc/mlos/tsysmalloc.h>
/* 组合 */
COMPOSE_MLAYER(wcet_test, wcet, tsysmalloc)

/* 定义tls */
DEF_MTLS_PTHREAD(GET_MLAYER_OBJNR(wcet_test), 4096, mlcc_palloc, mp_coreid)

/* 定义初始化过程 */
// #include <pthreadalt/init.inc.c>

#include <pthreadalt/pthreadalt_init.h>
DEF_PTHREADALT_INIT
// DEF_PTHREADALT_INIT_METALC_SOLIB

DEF_SYSINIT(mtls, wcet_test)
DEF_CFLOWFIN(mtls)
DEF_CFLOWINIT(mtls, wcet_test)
DEF_SYSFIN(__omega)

typedef struct bench_conf {
	size_t current_test_unitsize;
	size_t current_test_totalsz;
} bench_conf_t;

static recbatch_t *recs_arr[TEST_THREADNR + 1];

static bench_conf_t bench_conf;
static size_t total_exec_nr = 0;

static TLS_INITIAL cid_t mytid;

static void *bench_wcet(void *args){
	PARAM_USED(args);

	/* 根据核心ID制造不对称负载 */
	cid_t cid = mytid;
	/* 本次申请的负载 */
	size_t unit_size = bench_conf.current_test_unitsize;
	// size_t ori_max_cont = bench_conf.current_test_totalsz / unit_size;
	/* 不对称负载，当cid为0时取最大负载，其他cid依次递减，总量是一定的 */
	/* */
	size_t ori_max_cont = (bench_conf.current_test_totalsz / unit_size) / ((cid >> 1) + 1);
	// size_t real_max = bench_conf.current_test_totalsz / unit_size;
	size_t max_cont = ori_max_cont;

	/* 申请队列 */
	size_t memrec_maxnr = bench_conf.current_test_totalsz / unit_size;
	// void *recbatch_mem = page_alloc(recbatch_size(memrec_maxnr));
	recbatch_t *recbatch = recbatch_init(recs_arr[cid], recbatch_size(memrec_maxnr), memrec_maxnr);

	mreq_t req;
	req.tls = mtls_get();
	ASSERT(req.tls);
	size_t total = 0;
	while (total < TEST_NR){
		
		/* 申请一个批次 */
		for (word_t idx = 0; idx < max_cont; idx++){
			req.size = unit_size;
			// req.nr = 1;
			// req.align = 0;
			void *mem = wcet_test_alloc(&req);
			// void *mem = malloc(unit_size);
			ASSERT(mem);
			*(paddr_t *)mem = (paddr_t)(cid);
			/* 记录 */
			recbatch_push_rec(recbatch, mem, unit_size);
		}

		/* 打乱后挂到全局链表 */
		total = faa(&total_exec_nr, max_cont);
		recbatch_shuffle(recbatch, total);


		recbatch = recbatch_exchange_locked(recbatch);
		ASSERT(recbatch);

		/* 获得一个节点释放 */
		
		/* 获得上一个节点的申请数量 */
		max_cont = recbatch->used_nr;
		for (word_t idx = 0; idx < max_cont; idx++){
			/* 释放 */
			void *mem = recbatch_pop_rec(recbatch)->ptr;
			ASSERT(mem);
			req.ptr = mem;
			// req.size = unit_size;
			// req.nr = 1;
			wcet_test_free(&req);
			// free(mem);
		}
		
		// /* 防止取到空节点 */
		// if (max_cont == 0) {
		// 	// WCET_PRINTF("get 0 \n");
		// 	max_cont = ori_max_cont;
		// }
		// /* 防止取到上次的大量节点 */
		// if (max_cont > ori_max_cont){
		// 	max_cont = ori_max_cont;
		// }
		max_cont = ori_max_cont;
	}
	atm_strel(&recs_arr[cid], recbatch);

	return NULL;
}

static void bench_wcet_setparam(size_t unit_size, size_t total_sz){
	bench_conf.current_test_unitsize = unit_size;
	bench_conf.current_test_totalsz = total_sz;
}

__PERF_PARALLEL_FUNC_BINDCORE_CUSTOM(bench_wcet , mytid, TEST_NR, TEST_MAXTHREADS, HDEF_LITTLECORE_OFFST, total_exec_nr = 0, test_nrs_arr, WCET_PRINTF)

/* perf测试 */
int main(){
	/* 申请队列 */
	/* 按最大算 */
	size_t memrec_maxnr = TEST_MAXSZ_BATCH / 16;
	for (word_t idx = 0; idx <= TEST_THREADNR; idx++){
		void *recbatch_mem = page_alloc(recbatch_size(memrec_maxnr));
		ASSERT(recbatch_mem);
		recs_arr[idx] = (recbatch_t *)recbatch_mem;
	}
	recbatch_t *recbatch = recbatch_init(recs_arr[TEST_THREADNR], recbatch_size(memrec_maxnr), memrec_maxnr);
	
	/* 填入作为sentry */
	recbatch->node.next = NULL_PTR;
	tail->next = &recbatch->node;
	tail = &recbatch->node;
	// recbatch_exchange_locked(recbatch);
	// mp_wmb();
	/* 设置参数 */
	WCET_PRINTF("[wcet bench] start size = 16...");
	bench_wcet_setparam(16, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 32...");
	bench_wcet_setparam(32, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 48...");
	bench_wcet_setparam(48, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 64...");
	bench_wcet_setparam(64, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 96...");
	bench_wcet_setparam(96, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 128...");
	bench_wcet_setparam(128, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 192...");
	bench_wcet_setparam(192, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 256...");
	bench_wcet_setparam(256, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 384...");
	bench_wcet_setparam(384, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 512...");
	bench_wcet_setparam(512, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 768...");
	bench_wcet_setparam(768, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 1024...");
	bench_wcet_setparam(1024, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 1536...");
	bench_wcet_setparam(1536, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	WCET_PRINTF("[wcet bench] start size = 2048...");
	bench_wcet_setparam(2048, TEST_MAXSZ_BATCH);
	PERF_PARALLEL_RUN(bench_wcet);

	return 0;
}